
#include <BFile>
#include <BFolder>
#include <BFont>
#include <BStyle>
#include <BPainter>

#include <BHBoxLayout>
#include <BVBoxLayout>
#include <BGridLayout>
#include <BMessageBox>
#include <BGraphicWidget>
#include <BSystem>
#include <BShortcut>
#include <BApplication>

#include "TextEditor.h"
#include "TextFormat.h"
#include "HistoryDialog.h"
#include "MainDialog.h"

MainDialog::MainDialog(BWidget* parent) : BDialog(parent)
{

	_fileDialog = new FileDialog(this);

	BHBoxLayout* topLayout = new BHBoxLayout("top");
	{
		_openButton = new BButton(u8"打开");
		_openButton->setShortcut("CTRL+O");

		_saveButton = new BButton(u8"保存");
		_saveButton->setShortcut("ctrl+S");

		_revertButton = new BButton(u8"恢复");
		_revertButton->setShortcut("ctrl+r");

		topLayout->addSpring(100);
		topLayout->addWidget(_openButton);
		topLayout->addWidget(_saveButton);
		topLayout->addWidget(_revertButton);
		topLayout->addSpring(100);
	}

	_listWidget = new BListWidget(u8"文档列表");
	_listWidget->setMargin(3);
	{
		_createButton = new BButton(Form_IconOnly);
		_createButton->setTips(u8"添加文档");

		_removeButton = new BButton(Form_IconOnly);
		_removeButton->setTips(u8"删除文档");

		_copyButton = new BButton(Form_IconOnly);
		_copyButton->setTips(u8"复制文档");

		_pasteButton = new BButton(Form_IconOnly);
		_pasteButton->setTips(u8"粘贴文档");

		BHBoxLayout* hlayout = new BHBoxLayout(_listWidget, Part_Top);
		hlayout->addSpring();
		hlayout->addWidget(_createButton);
		hlayout->addWidget(_removeButton);
		hlayout->addWidget(_copyButton);
		hlayout->addWidget(_pasteButton);
		hlayout->setSizePolicy(Policy_Preferred);
	}

	_itemLineEdit = new BLineEdit(_listWidget);
	_itemLineEdit->setVisible(false);

	_tabWidget = new BTabWidget();

	BHBoxLayout* centerLayout = new BHBoxLayout();
	centerLayout->addWidget(_listWidget);
	centerLayout->addWidget(_tabWidget, 6);
	centerLayout->setSplitable(true);
	centerLayout->setSpacing(5);
	centerLayout->setHandleSize(3);

	_statusBar = new BStatusBar();
	_statusBar->setFadeTime(2);

	BVBoxLayout* vlayout = new BVBoxLayout(this);
	vlayout->addLayout(topLayout, 0);
	vlayout->addLayout(centerLayout);
	vlayout->addWidget(_statusBar, 0);

	connect(_openButton, Signal_Clicked, &MainDialog::slotOpenButtonClicked);
	connect(_saveButton, Signal_Clicked, &MainDialog::slotSaveButtonClicked);

	connect(_listWidget, Signal_ItemClicked, &MainDialog::slotListItemClicked);
	connect(_listWidget, Signal_ItemDoubleClicked, &MainDialog::slotListItemDoubleClicked);
	connect(_listWidget, Signal_Freshed, &MainDialog::slotListWidgetFreshed);
	connect(_listWidget, Signal_Framed, &MainDialog::slotListWidgetFramed);

	connect(_createButton, Signal_Clicked, &MainDialog::slotCreateButtonClicked);
	connect(_removeButton, Signal_Clicked, &MainDialog::slotRemoveButtonClicked);
	connect(_copyButton, Signal_Clicked, &MainDialog::slotCopyButtonClicked);
	connect(_pasteButton, Signal_Clicked, &MainDialog::slotPasteButtonClicked);
	connect(_itemLineEdit, Signal_EditFinished, &MainDialog::slotItemTextEditFinished);

	_saveButton->setEnabled(false);
	_revertButton->setEnabled(false);
}
MainDialog::~MainDialog()
{

}

bool MainDialog::openFile(const BString& fileName)
{
	if (!BFile::Exist(fileName))
		return false;
	if (BSonNode* root = _document.load(fileName))
	{
		_listWidget->clearItems();
		for (int i = 0; i < root->childCount(); i++)
		{
			BSonNode* child = root->child(i);
			BListItem* item = _listWidget->addItem(child->name());
			item->setAsset(child);
			item->setProperty("text", child->text());
			TextFormat* textFormat = new TextFormat();
			if (child->childCount())
			{
				BStringArray words;
				BString text;
				for (int s = 0; s < child->childCount(); s++)
				{
					BSonNode* formatNode = child->child(s);
					const BString& posStr = formatNode->attrib("pos");
					if (posStr.size())
					{
						int pos = posStr.toInt();
						int count = formatNode->attrib("count").toInt();
						text = formatNode->attrib("font");
						if (BFont* font = StringToFont(text))
						{
							textFormat->setFont(pos, count, font);
						}
						text = formatNode->attrib("color");
						if (text.size())
						{
							textFormat->setColor(pos, count, StringToColor(text));
						}
						text = formatNode->attrib("ground");
						if (text.size())
						{
							textFormat->setGround(pos, count, StringToColor(text));
						}
					}
					const BString& lineStr = formatNode->attrib("line");
					if (lineStr.size())
					{
						int line = lineStr.toInt();
						text = formatNode->attrib("spacing");
						if (text.size())
							textFormat->setLineSpacing(line, text.toInt());
						text = formatNode->attrib("align");
						if (text.size())
							textFormat->setLineAlign(line, StringToAlign(text));
						text = formatNode->attrib("height");
						if (text.size())
							textFormat->setLineHeight(line, text.toInt());
					}
				}
			}
			item->setProperty("format", textFormat);
		}
		_fileName = fileName;
	}
	BString message = u8"打开文件成功：";
	message << fileName;
	_statusBar->showMessage(message, 3);
	return true;
}
bool MainDialog::saveFile(const BString& fileName)
{
	_document.clear();
	_document.setFormat("{\n}\n");
	BSonNode* root = _document.addNode("root");
	for (int i = 0; i < _listWidget->itemCount(); i++)
	{
		BListItem* item = _listWidget->item(i);
		BSonNode* node = item->asset();
		node->clear();
		if (TextFormat* textFormat = item->property("format"))
		{
			const BMap<int, CodeItem>& codeItemMap = textFormat->codeItemMap();
			for (auto it = codeItemMap.begin(); it.valid(); ++it)
			{
				int pos = it.key();
				const CodeItem& codeItem = it.value();
				if (BSonNode* child = node->addChild("format"))
				{
					child->setAttrib("pos", pos);
					child->setAttrib("count", codeItem.count);
					if (const BFont* font = codeItem.font)
						child->setAttrib("font", StringFromFont(font));
					if (codeItem.color.a())
						child->setAttrib("color", StringFromColor(codeItem.color));
					if (codeItem.ground.a())
						child->setAttrib("ground", StringFromColor(codeItem.ground));
				}
			}
			const BMap<int, LineItem>& lineItemMap = textFormat->lineItemMap();
			for (auto it = lineItemMap.begin(); it.valid(); ++it)
			{
				int line = it.key();
				const LineItem& lineItem = it.value();
				if (BSonNode* child = node->addChild("format"))
				{
					child->setAttrib("line", line);
					if (Align align = lineItem.align)
						child->setAttrib("align", StringFromAlign(align));
					if (lineItem.height)
						child->setAttrib("line", lineItem.height);
					if (lineItem.spacing)
						child->setAttrib("spacing", lineItem.spacing);
				}
			}
		}
		root->addChild(node);
	}
	if (!_document.save(fileName))
	{
		BMessageBox::Warning(this, u8"消息", u8"保存文件失败！", Button_Ok, Button_Ok);
		return false;
	}
	BString message = u8"保存文件成功：";
	message << fileName;
	_statusBar->showMessage(message, 3);
	return true;
}

void MainDialog::signChanged(BWidget* widget, bool changed)
{
	const BString& title = widget->title();
	if (changed)
	{
		if (title.last() != '*')
		{
			BString newTitle;
			newTitle << title << "*";
			widget->setTitle(newTitle);
		}
	}
	else
	{
		if (title.last() == '*')
		{
			BString newTitle = title - '*';
			widget->setTitle(newTitle);
		}
	}
	widget->fresh();
	_saveButton->setEnabled(changed);
	_revertButton->setEnabled(changed);
}

void MainDialog::slotOpenButtonClicked(BObject* object, const BValue& value)
{
	const BString& fileName = _fileDialog->openFile(u8"打开笔记", "", u8"son格式笔记文件(*.nbs);xml格式笔记文件(*.nbx)");
	if (fileName.size())
	{
		if (openFile(fileName))
		{
			this->setName(fileName);
			this->setTitle(fileName);
			this->emit("file-opened", fileName);
		}
		else
		{
			BString text("Open resource file failed!\n");
			text << fileName;
			BMessageBox::Warning(this, "Warning", text);
		}
	}
}
void MainDialog::slotSaveButtonClicked(BObject* object, const BValue& value)
{
	TextEditor* textEdit = dynamic_cast<TextEditor*>(_tabWidget->current());
	if (textEdit->title().empty())
	{
		BMessageBox::Critical("请输入文本标题，方可进行保存！");
		return;
	}
	if (textEdit->property("dirty"))
	{
		if (textEdit->asset().empty())
		{
			BListItem* item = _listWidget->addItem(textEdit->title());
			BSonNode* node = new BSonNode(textEdit->title());
			item->setAsset(node);
			textEdit->setAsset(item);
		}
		BListItem* item = textEdit->asset();
		item->setProperty("text", textEdit->text());
		if (BSonNode* node = item->asset())
		{
			node->setText(textEdit->text());
		}
		textEdit->setProperty("dirty", false);
		textEdit->fresh();
		signChanged(_listWidget, true);
	}
	if (_listWidget->title().endWith('*'))
	{
		if (_fileName.empty())
		{
			_fileName = _fileDialog->saveFile(u8"打开笔记", "", u8"son格式笔记文件(*.nbs);xml格式笔记文件(*.nbx)");
			if (_fileName.empty())
				return;
			this->emit("file-opened", _fileName);
		}
		saveFile(_fileName);
		signChanged(_listWidget, false);
		_saveButton->setEnabled(false);
		_revertButton->setEnabled(false);
	}
}
void MainDialog::slotRevertButtonClicked(BObject* object, const BValue& value)
{

}

void MainDialog::slotListItemClicked(BObject* object, const BValue& value)
{
	if (BListItem* item = value)
	{
		if (_itemLineEdit->asset() != value)
		{
			_itemLineEdit->setAsset(value);
			_itemLineEdit->hide();
			return;
		}
		BRect crect = _listWidget->centerRect();
		BRect rect = item->rect();
		rect.left() = crect.left();
		rect.right() = crect.right();
		_itemLineEdit->setText(item->text());
		_itemLineEdit->setAsset(value);
		_itemLineEdit->setRect(rect);
		_itemLineEdit->popup();
		return;
	}
	_itemLineEdit->setAsset(value);
	_itemLineEdit->hide();
}
void MainDialog::slotListItemDoubleClicked(BObject* object, const BValue& value)
{
	if (TextEditor* textEdit = dynamic_cast<TextEditor*>(_tabWidget->current()))
	{
		if (textEdit->property("dirty"))
		{
			if (Button_Save == BMessageBox::Warning(u8"文本已经改变，\n是否要保存？", Button_Save | Button_Cancel))
			{
				_saveButton->click();
			}
		}
	}

	if (BListItem* item = value)
	{
		TextEditor* editor = new TextEditor();
		BString text = item->index() + 1;
		text.prepend('0', 3 - text.size());
		text << ' ' << item->text();
		editor->setTitle(text);
		BSonNode* node = item->asset();
		editor->setText(node->text());
		editor->setAsset(value);
		_tabWidget->addTab(editor);
		connect(editor, Signal_Changed, &MainDialog::slotTextEditChanged);
		connect(editor, Signal_TextEdited, &MainDialog::slotTextEditChanged);
		BString message = u8"打开文档：";
		message << text;
		_statusBar->showMessage(message, 3);
	}
}
void MainDialog::slotListWidgetFreshed(BObject* object, const BValue& value)
{
	int number = _listWidget->itemCount();
	BString numberStr = number;
	if (const BFont* font = _listWidget->realFont())
	{
		int width = numberStr.size() * font->codeSize('8').width();
		_listWidget->setPerch(Part_Left, width + 10);
	}
	if (BListItem* item = _itemLineEdit->asset())
	{
		BRect crect = _listWidget->centerRect();
		BRect rect = item->rect();
		rect.left() = crect.left();
		rect.right() = crect.right();
		_itemLineEdit->setRect(rect);
	}
}
void MainDialog::slotListWidgetFramed(BObject* object, const BValue& value)
{
	BPainter painter(_listWidget);
	BRect leftRect = _listWidget->rect(Part_Left);
	painter.setClip(leftRect);
	for (int i = 0; i < _listWidget->itemCount(); i++)
	{
		BListItem* item = _listWidget->item(i);
		BRect rect = item->rect();
		rect.left() = leftRect.left();
		rect.right() = leftRect.right();
		painter.setColor(Color_Text);
		painter.drawText(rect, i + 1, Align_Center);
	}
}

void MainDialog::slotCreateButtonClicked(BObject* object, const BValue& value)
{
	BString text;
	int num = 0;
	while (1)
	{
		text.reset();
		text << u8"新建文档" << num++;
		if (!_listWidget->item(text))
			break;
	}
	BListItem* item = new BListItem(text);
	if (BListItem* selectedItem = _listWidget->selectedItem())
	{
		_listWidget->insertItem(selectedItem->index(), item);
	}
	else
	{
		_listWidget->addItem(item);
	}
	item->setAsset(new BSonNode(text));
	item->setSelected(true);
	_itemLineEdit->setAsset(item);
	_itemLineEdit->setText(text);
	_itemLineEdit->show();
	_listWidget->flush();
	signChanged(_listWidget, true);
}
void MainDialog::slotRemoveButtonClicked(BObject* object, const BValue& value)
{
	if (BListItem* selectedItem = _listWidget->selectedItem())
	{
		_listWidget->removeItem(selectedItem);
		signChanged(_listWidget, true);
	}
}
void MainDialog::slotCopyButtonClicked(BObject* object, const BValue& value)
{

}
void MainDialog::slotPasteButtonClicked(BObject* object, const BValue& value)
{

}
void MainDialog::slotItemTextEditFinished(BObject* object, const BValue& value)
{
	if (BListItem* item = _itemLineEdit->asset())
	{
		const BString& text = _itemLineEdit->text();
		item->setText(text);
		if (BSonNode* node = item->asset())
		{
			node->setName(text);
		}
		_itemLineEdit->setText(BString());
		_itemLineEdit->setAsset(BValue());
		_itemLineEdit->hide();
		signChanged(_listWidget, true);
	}
}

void MainDialog::slotTextEditChanged(BWidget* widget, const BValue& value)
{
	signChanged(widget, true);
}

void MainDialog::closeEvent(const BEvent& event)
{
	if (_saveButton->enabled())
	{
		const BStyle* style = this->realStyle();
		Button button = BMessageBox::Warning(u8"注意", u8"笔记内容修改过，是否要保存？", Button_Save | Button_Cancel);
		if (button == Button_Cancel)
		{
			event.accept(false);
			return;
		}
		if (button == Button_Save)
		{
			_saveButton->click();
		}
	}
	BApplication::exit(0);
}

void MainDialog::styleEvent(const BEvent& event)
{
	BDialog::styleEvent(event);
	BStyle* style = event.value();
	_createButton->setIcon(style->icon("create"));
	_removeButton->setIcon(style->icon("remove"));
	_copyButton->setIcon(style->icon("copy"));
	_pasteButton->setIcon(style->icon("paste"));
}
